#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <sys/time.h>

#define MIN_SIZE 1
#define MAX_SIZE 65536
#define TIMES 1024

static int
timeval_substract (struct timeval *r,struct timeval *x, struct timeval *y);

double
convert_timeval (struct timeval *r, int *size);

double
convert_timevalToSec (struct timeval *r);

int main (void)
{
	int i = 0;
	int size = 0;
	int aux_size = 0;
	char * write_buffer = NULL; /* el buffer del cual se va a escribir */
	FILE * fifo = NULL;
	size_t err = 0;
	char go_on = 'a';
	struct timeval start, end,result;
	double speed = 0.0;

	write_buffer = (char *) calloc (MAX_SIZE, sizeof(char));
	assert (write_buffer != NULL);

	for (i=0; i < MAX_SIZE; i++)
		write_buffer[i] = 'a';

	fifo = fopen ("/dev/fifo", "w");
	assert (fifo != NULL);

	/** escribimos con los diferentes tamaños **/
	for (size=MIN_SIZE; size<=MAX_SIZE; size*=2)
	{
		printf("size=%d\n", size);
		err = gettimeofday(&start, NULL);
		assert (err == 0);
		for (i=0; i < TIMES; i++)
		{
			err = fwrite(write_buffer, sizeof(char), size, fifo);
			assert (err == size);
			err = fflush(fifo);
			assert (err == 0);
		}
		err= gettimeofday(&end, NULL);
		assert (err == 0);
		err = timeval_substract(&result, &end, &start);
		printf("tamaño total escrito: %d\n", size*TIMES); 
		printf("tiempo total: %6.6f\n", convert_timevalToSec(&result));
		assert (err == 0);
		aux_size = size*TIMES;
		speed = convert_timeval(&result, &aux_size);		
		printf("promedio con size=%d es %6.6fKb/s\n", size, speed);
		scanf("%c", &go_on);
	}

	err = fclose(fifo);
	assert (err == 0);

	free(write_buffer);
	write_buffer = NULL;
	
	return 0;
}

static int
timeval_substract (struct timeval *r,struct timeval *x, struct timeval *y)
{
       /* Perform the carry for the later subtraction by updating y. */
       if (x->tv_usec < y->tv_usec) {
         int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
         y->tv_usec -= 1000000 * nsec;
         y->tv_sec += nsec;
       }
       if (x->tv_usec - y->tv_usec > 1000000) {
         int nsec = (x->tv_usec - y->tv_usec) / 1000000;
         y->tv_usec += 1000000 * nsec;
         y->tv_sec -= nsec;
       }

       /* Compute the time remaining to wait.
          tv_usec is certainly positive. */
       r->tv_sec = x->tv_sec - y->tv_sec;
       r->tv_usec = x->tv_usec - y->tv_usec;

       /* Return 1 if result is negative. */
       return x->tv_sec < y->tv_sec;
}

double
convert_timeval (struct timeval *r, int *size)
{
	double result = 0.0;
	double sec = 0.0;
	double micro_sec = 0.0;
	double aux = 0.0;

	sec = r->tv_sec;
	micro_sec = r->tv_usec;

	/** pasamos los microsegundos a segundos **/
	micro_sec = micro_sec / (double)1000000;
	sec = sec+micro_sec;

	/** pasamos de bytes a Kilobytes y guardamos en aux **/
	aux = *size / (double)1024;

	result = aux/sec;

	return result;
}

double
convert_timevalToSec (struct timeval *r)
{

	double sec = 0.0;
	double micro_sec = 0.0;


	sec = r->tv_sec;
	micro_sec = r->tv_usec;

	/** pasamos los microsegundos a segundos **/
	micro_sec = micro_sec / (double)1000000;
	sec = sec+micro_sec;

	return sec;
}